/**
  ******************************************************************************
  * @file    SSL_client.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    31-October-2011
  * @brief   SSL Client main task
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************  
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SSL_SERVER_PORT 443 /* Server port number */
#define SSL_SERVER_NAME "192.168.1.8" /* Server address */
#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n" /* HTTP request */
#define BUF_SIZE      200
#define DEBUG_LEVEL   0   /* Set DEBUG_LEVEL if you want to enable SSL debug
                           option, this should be set to 2, 3, 4 or 5 */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* SSL structures */
rng_state rngs;
ssl_context ssl;
ssl_session ssn;

/* Private functions ---------------------------------------------------------*/
void my_debug(void *ctx, int level, const char *str)
{
  if(level < DEBUG_LEVEL)
  {
    printf("%s", str); 
  }
}

/**
  * @brief  SSL client task.
  * @param  pvParameters not used
  * @retval None
  */
void ssl_client(void *pvParameters)
{
  int ret = 0;
  int len = 0;
  int server_fd =0;
  unsigned char buf[1024];

  /* Initialize the session data */
  memset(&ssn, 0, sizeof(ssl_session));
  memset(&ssl, 0, sizeof(ssl_context));
    
  /* Start the connection */
  do
  {
    printf(( "\n\rSSL : Start the connection \n\r"));
    printf("\n\rConnecting to tcp/%s/ Port:%4d...", SSL_SERVER_NAME, SSL_SERVER_PORT); 
 
    /* Bint the connection to SSL server port */
    ret = net_connect(&server_fd, SSL_SERVER_NAME, SSL_SERVER_PORT);
    if(ret != 0)
    {
      /* Connection to SSL server failed */
      printf(" failed \n\r ! net_connect returned %d\n\r", -ret);
      
      /* Wait 1s until next retry */
      vTaskDelay(1000);
    } 
  }while(ret!=0);

  printf((" Ok \n\r"));

  /* Setup the SSL session */
  printf("\n\rSetting up the SSL/TLS structure...");

  /* Initialize the SSL context */
  ret = ssl_init(&ssl);
  if(ret != 0)
  {
    /* SSL initialization failed */
    printf(" failed \n\r ! ssl_init returned %d\n\r", -ret);
    goto exit;
  }
  printf((" ok\n\r"));
  
  /* Set the current session as SSL client */
  ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
  
  /* No certificate verification */
  ssl_set_authmode(&ssl, SSL_VERIFY_NONE);

  /* Set the random number generator callback function */
  ssl_set_rng(&ssl, RandVal, &rngs); 
  
  /* Set the debug callback function */
  ssl_set_dbg(&ssl, my_debug, stdout);

  /* Set read and write callback functions */
  ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd);

  /* Set the session resuming flag, timeout and session context */
  ssl_set_session(&ssl, 1, 600, &ssn);

  /* The list of ciphersuites to be used in this session */
  ssl_set_ciphersuites(&ssl, ssl_default_ciphersuites);
 
  /* Write the GET request to SSL server */
  printf("\n\r=> Write to server :" );
  len = sprintf((char *) buf, GET_REQUEST);
  
  /* Send application data to be encrypted */
  ret = ssl_write(&ssl, buf, len);
  
  while(ret <= 0)
  {
    if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
    {
      /* Write to SSL server failed */
      printf( " failed \n\r! ssl_write returned %d\n\r", -ret);
      goto exit;
    }
  }

  /* Display application data */
  len = ret;
  printf("\n\r-----------------------------------------------------------\n\r");
  printf( "%s", (char *) buf );
  printf("\n\r-----------------------------------------------------------\n\r");
  printf( "\nSuccessfully write %d bytes to server\n\r", len);

  /* Read the HTTP response */
  printf("\n\r<= Read from server :");
  do
  {
    len = sizeof(buf) - 1;

    memset(buf, 0, sizeof(buf));

    /* Read decrypted application data */
    ret = ssl_read(&ssl, buf, len);	
    
    if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE ) 
    {
      printf("SSL: POLARSSL_ERR_NET_WANT_READ/WRITE\n");
      continue;
    }
    if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY ) 
    {
      printf("SSL: POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY\n");
      break;
    } 
    if( ret <= 0 )
    {
      printf( "failed\n  ! ssl_read returned %d\n\n", ret );
      break;
    }

    /* Display decrypted application data */
    len = ret;				
    printf("\n\r---------------------------------------------------------\n\r");
    printf( "%s", (char *) buf );
    printf("\n\r---------------------------------------------------------\n\r");
    printf("\n\rSuccessfully read %d bytes from server\n",len);
  }while(0);

exit:
  /* Close and delete the current session data */
  printf("\n\rSSL : End of connection \n");
  net_close(server_fd);
  ssl_free(&ssl);
  memset(&ssl, 0, sizeof(ssl));

  /* Infinite loop */
  for( ;; ) 
  {
    /* Toggle LD1 */
    STM_EVAL_LEDToggle(LED1);

    /* Insert 400 ms delay */
    vTaskDelay(400);
  }
}

/**
  * @brief  Returns a 32-bit random number.
  * @param  arg not used
  * @retval 32-bit random number
  */
int RandVal(void* arg)
{
  uint32_t ret; 

  /* Wait until random number is ready */
  while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET);
  
  /* Get the random number */       
  ret = RNG_GetRandomNumber();

  /* Return the random number */ 
  return(ret);
}

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
